#pragma once

#include <cassert>
#include <condition_variable>
#include <lyn_api.h>
#include <mutex>
#include <queue>
#include <semaphore.h>
#include <list>
#include "util.hpp"

class EventPool
{
public:
    EventPool(int iPoolSize = 9999)
        : m_iCurPoolSize(0), m_iPoolSize(iPoolSize), m_iPopCount(0),
          m_iPushCount(0)
    {
    }

    EventPool() {}

    ~EventPool()
    {
        Release();
    }

    void init(int iPoolSize = 9999)
    {
        m_iCurPoolSize = 0;
        m_iPoolSize = iPoolSize;

        m_iPopCount = 0;
        m_iPushCount = 0;
    }

    // 获取对象
    lynEvent_t Pop()
    {
        std::unique_lock<std::mutex> lock(m_oMutex);

        while (m_listBuf.size() == 0 && m_iCurPoolSize == m_iPoolSize)
            m_oCondVar.wait(lock); // 等待放回

        lynEvent_t pEvent = nullptr;
        if (m_listBuf.size() == 0)
        {
            ++m_iCurPoolSize;
            CHECK_ERR(lynCreateEvent(&pEvent));
        }
        else
        {
            // std::cout << "m_listBuf.size()==== "
            //           << m_listBuf.size() << std::endl;
            pEvent = m_listBuf.front();
            m_listBuf.pop_front();
        }

        m_listBufUsed.push_back(pEvent);

        return pEvent;
    }

    // 还对象，使用frame的data指针
    void Push(lynEvent_t mEvent)
    {
        std::unique_lock<std::mutex> lock(m_oMutex);

        for (auto it = m_listBufUsed.begin(); it != m_listBufUsed.end(); it++)
        {
            mEvent = *it;
            m_listBuf.push_back(mEvent); // 放回内存池
            m_listBufUsed.erase(it);     // 去掉已用
            m_oCondVar.notify_one();

            return;
        }

        std::cout << "EventPool::Push is not find!!!" << std::endl;
    }

    // 释放空间
    void Release()
    {
        std::unique_lock<std::mutex> lock(m_oMutex);
        for (lynEvent_t pe : m_listBuf)
        {
            lynSynchronizeEvent(pe);
            CHECK_ERR(lynDestroyEvent(pe));
        }
        m_listBuf.clear();
    }

protected:
    std::mutex m_oMutex;
    std::condition_variable m_oCondVar;
    int m_iPoolSize;    // 内存池大小
    int m_iCurPoolSize; // 当前内存池大小
    int m_iPopCount;
    int m_iPushCount;
    std::list<lynEvent_t> m_listBuf;     // 可用对象列表
    std::list<lynEvent_t> m_listBufUsed; // 已经使用对象列表
};